package com.cn.tianxin.ssserver.ext;

import com.cn.tianxin.ssserver.utils.PropUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;

/**
 * 管理微信 acces_token类
 */
public class WXAccessToken {
    private String access_token;
    private int expires_in;
    private Date tokenBeginTime;    //token获取的时间

    private static WXAccessToken accessToken;    //全局持有1个token

    @Override
    public String toString() {
        return "WXAccessToken{" +
                "access_token='" + access_token + '\'' +
                ", expires_in=" + expires_in +
                ", tokenBeginTime=" + tokenBeginTime +
                '}';
    }

    private WXAccessToken(String access_token, int expires_in) {
        this.access_token = access_token;
        this.expires_in = expires_in;
        this.tokenBeginTime = new Date();
    }

    private static final String DEFAULT_ENCODE = "UTF-8";

    public static String mapToURLStr(Map<String,String> param){

        StringBuilder stringBuilder = new StringBuilder();
        Set<Map.Entry<String, String>> entries = param.entrySet();
        Iterator<Map.Entry<String, String>> iterator = entries.iterator();
        while (iterator.hasNext()){
            Map.Entry<String, String> next = iterator.next();
            String paramStr = "";
            try {
                if (iterator.hasNext()){
                    paramStr = next.getKey() + "=" + URLEncoder.encode(next.getValue(), DEFAULT_ENCODE)+"&";
                }else {
                    paramStr = next.getKey() + "=" + URLEncoder.encode(next.getValue(), DEFAULT_ENCODE);
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();    //impossible
            }
            stringBuilder.append(paramStr);
        }

        return stringBuilder.toString();
    }

    public static WXAccessToken getToken(){
        //http 请求获取
        if (WXAccessToken.accessToken != null && !WXAccessToken.accessToken.isExpired()){
            return WXAccessToken.accessToken;
        }

        // httpclient 获取微信的access_token
        PropUtil propUtil = null;
        try {
            propUtil = PropUtil.getPropUtilFromMap("weixin.properties");
            String urlStr = "https://api.weixin.qq.com/cgi-bin/token";

            URL url = new URL(urlStr);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            //httpURLConnection.setRequestMethod("POST");
            httpURLConnection.setRequestMethod("GET");    //只能使用get
            httpURLConnection.setConnectTimeout(10*1000);
            httpURLConnection.setReadTimeout(10*1000);
            httpURLConnection.setDoOutput(true);

            Map<String,String> params = new HashMap<>();
            params.put("grant_type","client_credential");
            params.put("appid",propUtil.get("appId"));
            params.put("secret",propUtil.get("secret"));
            String paramStr = mapToURLStr(params);
            OutputStream outputStream = httpURLConnection.getOutputStream();
            outputStream.write(paramStr.getBytes(DEFAULT_ENCODE));
            httpURLConnection.connect();

            InputStream inputStream = httpURLConnection.getInputStream();
            int available = inputStream.available();
            byte[] bytes = new byte[available];
            inputStream.read(bytes);

            if (inputStream!=null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream!=null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            int responseCode = httpURLConnection.getResponseCode();
            String msg = new String(bytes,"UTF-8");
            ObjectMapper mapper = new ObjectMapper();
            JsonNode jsonNode = mapper.readTree(msg);
            if (jsonNode.get("access_token")!=null && jsonNode.get("expires_in")!=null){
                WXAccessToken.accessToken = new WXAccessToken(jsonNode.get("access_token").asText(),jsonNode.get("expires_in").asInt());
            }else {
                System.out.println("WXAccessToken.getToken=>"+jsonNode);
                WXAccessToken.accessToken = null;
            }

        } catch (IOException e) {
            e.printStackTrace();
            WXAccessToken.accessToken = null;
        }

        return WXAccessToken.accessToken;

    }

    public String getAccess_token() {
        return access_token;
    }

    //判断token是否过期    过期返回true,否则返回true
    private boolean isExpired(){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(this.tokenBeginTime);
        calendar.add(Calendar.SECOND,this.expires_in-30);    //提前三十秒认为过期，重新获取token
        //calendar.add(Calendar.SECOND,this.expires_in-7190);    //used for test

        return new Date().after(calendar.getTime());
    }

    public static void main(String[] args) throws InterruptedException {
        WXAccessToken token = WXAccessToken.getToken();
        if (token!=null){
            System.out.println("token.getAccess_token()=>"+token);
            System.out.println("token.isExpired()=>"+token.isExpired());
        }

        WXAccessToken token2 = WXAccessToken.getToken();
        if (token2!=null){
            System.out.println("token.getAccess_token()=>"+token2);
            System.out.println("token.isExpired()=>"+token2.isExpired());
        }

        Thread.sleep(9*1000);
        WXAccessToken token3 = WXAccessToken.getToken();
        if (token3!=null){
            System.out.println("token.getAccess_token()=>"+token3);
            System.out.println("token.isExpired()=>"+token3.isExpired());
        }

        Thread.sleep(10*1000);
        WXAccessToken token4 = WXAccessToken.getToken();
        if (token4!=null){
            System.out.println("token.getAccess_token()=>"+token4);
            System.out.println("token.isExpired()=>"+token4.isExpired());
        }

        Thread.sleep(11*1000);
        WXAccessToken token5 = WXAccessToken.getToken();
        if (token5!=null){
            System.out.println("token.getAccess_token()=>"+token5);
            System.out.println("token.isExpired()=>"+token5.isExpired());
        }

        //test ok
    }

}
